﻿using ChoMy.Areas.Admin.Models;
using ChoMy.Constants;
using ChoMy.Models;
using ChoMy.Models.Data;
using PagedList;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.Mvc;

namespace ChoMy.Areas.Admin.Controllers
{
    public class StyleController : Controller
    {
        private ChoMyContext db = new ChoMyContext();
        private string title = "giá sản phẩm";

        public StyleController()
        {
            ViewBag.Title = title;
        }

        [Authorize(Roles = "Admin, Style Read Public, Style Read Private")]
        public ActionResult Index(int? productId, bool? isTrash, string sortOrder, int? page, int? pageSize)
        {
            if (productId == null)
            {
                return RedirectToAction("BadRequest", "Error");
            }

            Product product = db.Products.Find(productId);

            if (product == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            ViewBag.Product = product;

            var sortList = new List<string> { "Property.Name", "Width", "Height", "DateModified", "DateCreated" };
            var pageSizeList = new List<int> { 10, 25, 50, 100 };
            int pageNumber = page ?? 1;

            pageSize = pageSize ?? 10;
            sortOrder = sortOrder ?? "DateCreated_desc";
            isTrash = isTrash ?? false;

            ViewBag.IsTrash = isTrash;
            ViewBag.PageSize = pageSize;
            ViewBag.PageSizeDDL = new SelectList(pageSizeList, pageSize);
            ViewBag.ReturnListUrl = Request.Url.AbsoluteUri;

            IQueryable<Style> query = db.Styles.Where(x => x.ProductId == product.Id);

            if (User.IsInRole("Style Read Private"))
            {
                query = query.Where(x => x.CreatedBy == User.Identity.Name);
            }

            ViewBag.TrashCount = query.Count(x => x.IsDelete);
            ViewBag.ListCount = query.Count(x => !x.IsDelete);

            query = Sort(query, sortOrder, sortList);

            query = query.Where(x => x.IsDelete == isTrash);

            ViewBag.PropertyTypes = product
                .Category.CategoryPropertyTypes
                .Select(x => x.PropertyType)
                .OrderBy(x => x.Name)
                .ToList();

            return View(query.ToPagedList(pageNumber, (int)pageSize));
        }

        [Authorize(Roles = "Admin, Style Read Public,  Style Read Private")]
        public ActionResult _Details(int id)
        {
            Style style = db.Styles.Find(id);

            if (User.IsInRole("Style Read Private") && style.CreatedBy != User.Identity.Name)
            {
                return null;
            }

            return PartialView(style);
        }

        [Authorize(Roles = "Admin, Style Create")]
        public ActionResult Create(int? productId, string returnListUrl)
        {
            if (productId == null)
            {
                return RedirectToAction("BadRequest", "Error");
            }

            Product product = db.Products.Find(productId);

            if (product == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            ViewBag.Product = product;

            PropertyDDL(product, new List<int>());

            ViewBag.ReturnListUrl = returnListUrl;

            return View();
        }

        [HttpPost]
        [Authorize(Roles = "Admin, Style Create")]
        [ValidateAntiForgeryToken]
        public ActionResult Create(StyleCreator model, string returnListUrl)
        {
            Product product = db.Products.Find(model.ProductId);

            if (ModelState.IsValid)
            {
                Style style = new Style();
                style.UnitPrice = model.UnitPrice;
                style.ProductId = model.ProductId;
                style.Quantity = model.Quantity;

                db.Styles.Add(style);
                db.SaveChanges();

                if (model.Properties != null)
                {
                    foreach (int prop in model.Properties)
                    {
                        if (prop != 0)
                        {
                            var sp = new StyleProperty();
                            sp.StyleId = style.Id;
                            sp.PropertyId = prop;

                            db.StyleProperties.Add(sp);
                            db.SaveChanges();
                        }
                    }
                }

                string productName = String.Format("{0} - {1}", product.Name, product.Code);

                SaveHistory("Create", productName, style.Id);
                AlertHandling("Create", productName, style.Id);

                if (!String.IsNullOrWhiteSpace(returnListUrl))
                {
                    return Redirect(returnListUrl);
                }

                return RedirectToAction("Index", new { productId = style.ProductId });
            }

            ViewBag.Product = product;

            PropertyDDL(product, new List<int>());           

            ViewBag.ReturnListUrl = returnListUrl;

            return View(model);
        }

        [Authorize(Roles = "Admin, Style Edit Public, Style Edit Private")]
        public ActionResult Edit(int? id, string returnListUrl)
        {
            if (id == null)
            {
                return RedirectToAction("BadRequest", "Error");
            }

            Style style = db.Styles.Find(id);

            if (style == null)
            {
                return RedirectToAction("NotFound", "Error");
            }

            if (User.IsInRole("Style Edit Private") && style.CreatedBy != User.Identity.Name)
            {
                return RedirectToAction("Unauthorized", "Error");
            }

            Product product = style.Product;

            ViewBag.Product = product;

            List<int> ids = style.StyleProperties.Select(x => x.PropertyId).ToList();

            PropertyDDL(style.Product, ids);

            var model = new StyleEditor();
            model.Id = style.Id;
            model.UnitPrice = style.UnitPrice;
            model.Quantity = style.Quantity;

            ViewBag.ReturnListUrl = returnListUrl;

            return View(model);
        }

        [HttpPost]
        [Authorize(Roles = "Admin, Style Edit Public, Style Edit Private")]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(StyleEditor model, string returnListUrl)
        {
            Style style = db.Styles.Find(model.Id);

            if (ModelState.IsValid)
            {
                style.UnitPrice = model.UnitPrice;
                style.Quantity = model.Quantity;
                style.DateModified = DateTime.Now;
                style.ModifiedBy = User.Identity.Name;

                db.Entry(style).State = EntityState.Modified;
                db.SaveChanges();

                db.StyleProperties.RemoveRange(style.StyleProperties);
                db.SaveChanges();

                if (model.Properties != null)
                {
                    foreach (int prop in model.Properties)
                    {
                        if (prop != 0)
                        {
                            var sp = new StyleProperty();
                            sp.StyleId = style.Id;
                            sp.PropertyId = prop;

                            db.StyleProperties.Add(sp);
                            db.SaveChanges();
                        }
                    }
                }

                string productName = String.Format("{0} - {1}", style.Product.Name, style.Product.Code);

                SaveHistory("Edit", productName, style.Id);
                AlertHandling("Edit", productName, style.Id);

                if (!String.IsNullOrWhiteSpace(returnListUrl))
                {
                    return Redirect(returnListUrl);
                }

                return RedirectToAction("Index", new { id = style.ProductId });
            }

            Product product = style.Product;

            ViewBag.Product = product;

            List<int> ids = style.StyleProperties.Select(x => x.PropertyId).ToList();

            PropertyDDL(product, ids);           

            ViewBag.ReturnListUrl = returnListUrl;

            return View(model);
        }

        [HttpPost]
        [Authorize(Roles = "Admin, Style Delete Public, Style Delete Private")]
        [ValidateAntiForgeryToken]
        public ActionResult Delete(int id, string returnListUrl)
        {
            Style style = db.Styles.Find(id);

            if (User.IsInRole("Style Delete Private") && style.CreatedBy != User.Identity.Name)
            {
                return RedirectToAction("Unauthorized", "Error");
            }

            int productId = style.ProductId;
            string productName = String.Format("{0} - {1}", style.Product.Name, style.Product.Code);

            db.Styles.Remove(style);
            db.SaveChanges();

            SaveHistory("Delete", productName, productId);
            AlertHandling("Delete", productName, productId);

            if (!String.IsNullOrWhiteSpace(returnListUrl))
            {
                return Redirect(returnListUrl);
            }

            return RedirectToAction("Index", new { productId = productId, isTrash = true });
        }

        [HttpPost]
        [Authorize(Roles = "Admin, Style Recycle Public, Style Recycle Private")]
        public ActionResult Recycle(int id)
        {
            Style style = db.Styles.Find(id);

            if (User.IsInRole("Style Recycle Private") && style.CreatedBy != User.Identity.Name)
            {
                return Json(-1, JsonRequestBehavior.AllowGet);
            }

            style.IsDelete = style.IsDelete ? false : true;
            style.DateModified = DateTime.Now;
            style.ModifiedBy = User.Identity.Name;

            db.Entry(style).State = EntityState.Modified;
            db.SaveChanges();

            string productName = String.Format("{0} - {1}", style.Product.Name, style.Product.Code);

            if (style.IsDelete)
            {
                SaveHistory("Recycle-Delete", productName, style.Id);
            }
            else
            {
                SaveHistory("Recycle-Restore", productName, style.Id);
            }

            return Json(style.IsDelete ? 1 : 0, JsonRequestBehavior.AllowGet);
        }

        #region Helpers
        private void SaveHistory(string crud, string productName, int id)
        {
            string type = "Style";

            DateTime dateTime = DateTime.Now;
            string userName = User.Identity.Name;
            string description = "";

            switch (crud)
            {
                case "Create":
                    description = String.Format("<b>{0}</b> tạo mới {1} <b>{2}</b> (ID: <b>{3}</b>)", userName, title, productName, id);
                    break;
                case "Edit":
                    description = String.Format("<b>{0}</b> chỉnh sửa {1} <b>{2}</b> (ID: <b>{3}</b>)", userName, title, productName, id);
                    break;
                case "Delete":
                    description = String.Format("<b>{0}</b> xóa vĩnh viễn {1} <b>{2}</b> (ID: <b>{3}</b>)", userName, title, productName, id);
                    break;
                case "Recycle-Delete":
                    description = String.Format("<b>{0}</b> xóa tạm thời {1} <b>{2}</b> (ID: <b>{3}</b>)", userName, title, productName, id);
                    break;
                case "Recycle-Restore":
                    description = String.Format("<b>{0}</b> khôi phục {1} <b>{2}</b> (ID: <b>{3}</b>)", userName, title, productName, id);
                    break;
            }

            var history = new History();
            history.DateTime = dateTime;
            history.Description = description;
            history.HistoryTypeId = db.HistoryTypes.First(x => x.Name == type).Id;

            db.Histories.Add(history);
            db.SaveChanges();
        }

        private void AlertHandling(string crud, string productName, int id)
        {
            string userName = User.Identity.Name;
            string alertMessage = "";

            switch (crud)
            {
                case "Create":
                    alertMessage = String.Format("Bạn vừa tạo mới {0} <b>{1}</b> (ID: <b>{2}</b>)", title, productName, id);
                    break;
                case "Edit":
                    alertMessage = String.Format("Bạn vừa chỉnh sửa {0} <b>{1}</b> (ID: <b>{2}</b>)", title, productName, id);
                    break;
                case "Delete":
                    alertMessage = String.Format("Bạn vừa xóa vĩnh viễn {0} <b>{1}</b> (ID: <b>{2}</b>)", title, productName, id);
                    break;
            }

            if (!String.IsNullOrWhiteSpace(alertMessage))
            {
                Session["alert-message-" + userName] = alertMessage;
                Session["alert-type-" + userName] = "alert-success";
            }
        }

        private void PropertyDDL(Product product, List<int> propertyIds)
        {
            List<PropertyType> propertyTypes = product.Category.CategoryPropertyTypes
                .Select(x => x.PropertyType)
                .OrderBy(x => x.Name)
                .ToList();

            ViewBag.PropertyTypes = propertyTypes;

            foreach (var pType in propertyTypes)
            {
                if (pType.NameId == "color" && product.Images.Any(x => x.PropertyId != null))
                {
                    ViewData[pType.NameId + "DDL"] =
                        product.Images
                        .Where(x => x.PropertyId != null)
                        .GroupBy(x => x.Property)
                        .Select(x => new SelectListItem
                        {
                            Text = x.Key.Name,
                            Value = x.Key.Id.ToString(),
                            Selected = propertyIds.Contains(x.Key.Id)
                        }).ToList();
                }
                else
                {
                    ViewData[pType.NameId + "DDL"] = db.Properties
                        .Where(x => x.PropertyTypeId == pType.Id)
                        .Select(x => new SelectListItem
                        {
                            Text = x.Name,
                            Value = x.Id.ToString(),
                            Selected = propertyIds.Contains(x.Id)
                        }).ToList();
                }
            }
        }

        private IQueryable<Style> Sort(IQueryable<Style> query, string sortOrder, List<string> sortList)
        {
            ViewBag.SortOrder = sortOrder;

            foreach (string sort in sortList)
            {
                ViewData[sort + "Sort"] = sortOrder == sort + "_desc" ? sort : sort + "_desc";
            }

            if (sortOrder.Contains("_desc"))
            {
                sortOrder = sortOrder.Replace("_desc", "");
                query = query.OrderBy(sortOrder + " descending");
                ViewData[sortOrder + "Icon"] = DataTableConstant.DescSortIcon;
            }
            else
            {
                query = query.OrderBy(sortOrder);
                ViewData[sortOrder + "Icon"] = DataTableConstant.AscSortIcon;
            }

            return query;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }

            base.Dispose(disposing);
        }
        #endregion
    }
}